WPF Diagrams includes built-in visual styles for the predefined DiagramConnection class, which can be extended by setting the LineType and configuring a suitable LineTypeLayout resource.
You will usually need to customise connection visuals at the Foundation level only you are creating your own diagram type and need to implement your own connection data model or connectivity logic. Even then, most requirements can be met by extending DiagramConnection and adding suitable connectivity logic to node classes, rather than implementing a whole new connection type.
However if you do need to rip and replace connection visuals then you can do so by defining a Style and hooking up that style to the DiagramSurface through the Formatter property.
Creating a Custom Connection Style
Most customisation of connection appearance can be carried out by creating one or more Styles in your XAML representing the appearance you require. You must then create a StyleSelector which references these styles. In most cases, you will create only one Style, and will use a FixedStyleSelector to select it. (The use of a selector is to provide additional flexibility for special scenarios.)
Your style must have a TargetType of DiagramConnectionElement, and will typically set the Template property to replace the control template. DiagramConnectionElement control templates are often relatively complex because a connection has lots of parts. A full example is shown in the CustomStyle sample. Your ControlTemplate will typically define the following elements.
- A Canvas on which the following elements are placed.
- A Path representing the connection itself. The Path.Data property should be derived from the Segments property of the bound IDiagramConnection, using a suitable converter such as the CorneredConnectionPathConverter. The Path’s Style is typically inherited from the containing DiagramConnectionElement using a RelativeSource binding, but it can be applied directly. This Path is what determines the geometry and appearance of the connection.
- A Path whose Data property is the same as the main Path (data bound), but which has a larger StrokeThickness and a transparent Stroke (#00FFFFFF). The purpose of this is to enable users to select the connection by clicking near the connection—otherwise selecting the connection would require pixel accuracy.
- A Path whose Data property is the same as the main Path (data bound), but which has a larger StrokeThickness and whose Visibility is Collapsed, plus a DataTrigger to set its Visibility to Visible when the containing DiagramConnectionElement is selected. The purpose of this is to highlight the connection when it is selected.
- One or two Paths representing the arrowhead(s). You can also use ContentControls whose ContentTemplate is {TemplateBinding StartArrowTemplate} (or EndArrowTemplate) and suitable rotation and translation transforms – this allows arrow drawing to be delegated back to a default. See the CustomStyle sample for an example.
- A TextBox or other control to show and allow editing of the connection caption. Again, you can instead specify a ContentPresenter instead of a specific control to delegate content display back to a default.
- An ItemsControl whose ItemsSource is the DiagramConnectionElement.MovableSegments and whose ItemTemplate consists of a DiagramSegmentThumb. The ItemPanelTemplate for this ItemsControl is typically a Canvas and the DiagramSegmentThumbs are positioned by binding the Canvas.Left and Canvas.Top properties in ItemContainerStyle to the Midpoint.X and Midpoint.Y properties of the segment. The Visibility of the ItemsControl should be set to Collapsed, with a DataTrigger to make it visible when the mouse is over the connection.
- Two ConnectionRelocatorThumb controls, positioned over the From and To connection points. The Visibility of these controls should be set to Collapsed, with a DataTrigger to make them visible when the mouse is over the connection.
- A ConnectionPointThumb to be displayed as the dynamic connection point when the user drags the end of another connection near to this connection. The position of this shape should be bound to DiagramConnectionElement.RequestedConnectionPoint and the Visibility should be Collapsed, with a DataTrigger to make it visible when DiagramConnectionElement.IsRequestingConnectionPoint is true.
Selecting the New Style
Once you have created this style, you must create a StyleSelector to select it. If you are using the same style for all connections, as is typical, you can use the FixedStyleSelector for this.
Finally you must create a DiagramFormatter instance which references your StyleSelector.
For a worked example, please refer to the CustomStyle sample.